package com.cloudsdo.cameratest.core;

import android.content.Context;
import android.graphics.Rect;
import android.os.Environment;
import android.util.Log;

import com.arcsoft.face.ErrorInfo;
import com.arcsoft.face.FaceEngine;
import com.arcsoft.face.FaceFeature;
import com.arcsoft.face.FaceInfo;
import com.arcsoft.face.FaceSimilar;
import com.arcsoft.face.VersionInfo;
import com.cloudsdo.cameratest.dao.Student;
import com.cloudsdo.cameratest.model.StuData;
import com.cloudsdo.cameratest.widget.FaceRectView;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

public class RecognizeService {
    private static final String TAG = "FaceHelper";
    private ExecutorService executor = Executors.newSingleThreadExecutor();
    private Context context;
    /**
     * fr 线程数，建议和ft初始化时的maxFaceNum相同
     */
    private int frThreadNum = 5;
    private boolean frThreadRunning = false;
    private FaceRectView.FaceListener faceListener;
    private LinkedBlockingQueue<FaceRecognizeRunnable> faceRecognizeRunnables;

    private RecognizeService(Builder builder) {
        context=builder.context;
        faceListener=builder.faceListener;
        if (builder.frThreadNum > 0) {
            frThreadNum = builder.frThreadNum;
            faceRecognizeRunnables = new LinkedBlockingQueue<FaceRecognizeRunnable>(frThreadNum);
        } else {
            Log.e(TAG, "frThread num must > 0,now using default value:" + frThreadNum);
        }
    }

    /**
     * 请求获取人脸特征数据
     *
     * @param nv21     图像数据
     * @param width    图像宽度
     * @param height   图像高度
     * @param format   图像格式
     */
    public void requestFaceFeature(byte[] nv21, int width, int height, int format) {
        if (faceRecognizeRunnables != null && faceRecognizeRunnables.size() < frThreadNum && !frThreadRunning) {
            faceRecognizeRunnables.add(new FaceRecognizeRunnable(nv21, width, height, format));
            executor.execute(faceRecognizeRunnables.poll());
        }
    }

    /**
     * 人脸特征提取线程
     */
    public class FaceRecognizeRunnable implements Runnable {
        private int width;
        private int height;
        private int format;
        private byte[] nv21Data;

        private FaceRecognizeRunnable(byte[] nv21Data, int width, int height, int format) {
            if (nv21Data == null) {
                return;
            }
            this.nv21Data = nv21Data;
            this.width = width;
            this.height = height;
            this.format = format;
        }

        @Override
        public void run() {
            frThreadRunning = true;

            int MAX_DETECT_NUM = 10;
            int orient= FaceEngine.ASF_OP_0_HIGHER_EXT;
            FaceEngine faceEngine = new FaceEngine();

//            int afCode = faceEngine.init(context, FaceEngine.ASF_DETECT_MODE_VIDEO, orient,
//                    16, MAX_DETECT_NUM, FaceEngine.ASF_AGE | FaceEngine.ASF_GENDER | FaceEngine.ASF_FACE3DANGLE | FaceEngine.ASF_LIVENESS);
            int afCode = faceEngine.init(context, FaceEngine.ASF_DETECT_MODE_VIDEO, orient,
                    16, MAX_DETECT_NUM, FaceEngine.ASF_AGE | FaceEngine.ASF_GENDER | FaceEngine.ASF_FACE3DANGLE | FaceEngine.ASF_FACE_RECOGNITION | FaceEngine.ASF_FACE_DETECT | FaceEngine.ASF_LIVENESS);
            VersionInfo versionInfo = new VersionInfo();
            faceEngine.getVersion(versionInfo);

            if (afCode == ErrorInfo.MOK) {

            }else{
                return;
            }

            if (nv21Data != null) {
                if (faceEngine != null) {
                    List<FaceInfo> faceInfoList = new ArrayList<>();
                    int code = faceEngine.detectFaces(nv21Data, width, height, format, faceInfoList);
                    if (code == ErrorInfo.MOK && faceInfoList.size() >0) {
                        //人脸检测成功并且检测到了人脸的情况
                        Log.e(TAG,"人脸检测成功");
                        drawPreviewInfo(faceInfoList);
//                        int faceProcessCode  = faceEngine.process(nv21Data, width, height, format, faceInfoList,FaceEngine.ASF_LIVENESS);
                        int faceProcessCode = faceEngine.process(nv21Data, width, height, format, faceInfoList, FaceEngine.ASF_AGE | FaceEngine.ASF_GENDER | FaceEngine.ASF_FACE3DANGLE |FaceEngine.ASF_LIVENESS);
                        if (faceProcessCode == ErrorInfo.MOK){
                            List ageInfoList = new ArrayList<>();
                            List genderInfoList = new ArrayList<>();
                            List face3DAngleList = new ArrayList<>();
                            List faceLivenessInfoList = new ArrayList<>();
                            int ageCode = faceEngine.getAge(ageInfoList);
                            int genderCode = faceEngine.getGender(genderInfoList);
                            int face3DAngleCode = faceEngine.getFace3DAngle(face3DAngleList);
                            int livenessCode = faceEngine.getLiveness(faceLivenessInfoList);
                            if (livenessCode == ErrorInfo.MOK){
                                //活体检测成功
                                Log.e(TAG,"活体检测成功");
                                FaceUtil.keepMaxFace(faceInfoList);
                                FaceFeature faceFeature = new FaceFeature();
                                int featureCode = faceEngine.extractFaceFeature(nv21Data, width, height, format, faceInfoList.get(0), faceFeature);
                                if (featureCode == ErrorInfo.MOK) {
                                    //特征提取成功
                                    //特征对比
                                    Log.e(TAG,"特征提取成功");
                                    for(int i = 0; i< StuData.getInstance(context).getFaceFeatureList().size(); i++){
                                        FaceFeature item=StuData.getInstance(context).getFaceFeatureList().get(i);
                                        FaceSimilar faceSimilar = new FaceSimilar();
                                        int sim=faceEngine.compareFaceFeature(faceFeature,item,faceSimilar);
                                        if (sim == ErrorInfo.MOK){
                                            //比对成功，可查看faceSimilar中的相似度
                                            Log.e(TAG,"比对成功，可查看faceSimilar中的相似度:"+faceSimilar.getScore());
                                            if(faceSimilar.getScore()>0.5){
                                                Student student=StuData.getInstance(context).getStudentFaceFeatureHashMap().get(item);
                                                if(student!=null){
                                                    String name=student.getName()+"";
                                                    if(student.isCheck()){
                                                        Log.e(TAG,name+"已晨检过");
                                                    }else{
                                                        student.setCheck(true);
                                                        Log.e(TAG,"欢迎"+name+"小朋友");
                                                    }
                                                }
                                            }
                                        }else{
                                            //比对失败，可根据code查看原因
                                            Log.e(TAG,"比对失败"+sim);
                                        }
                                    }
                                }else{
                                    Log.e(TAG,"特征提取失败 "+featureCode);
                                    //特征提取失败，可根据code查看原因
                                }

                            }else{
                            }
                            if(face3DAngleCode==ErrorInfo.MOK){
                                Log.e(TAG,face3DAngleList.toString());
                            }

                        }else{
                            //失败的情况
                            Log.e(TAG,"process失败 "+faceProcessCode);
                        }
                    }else{
                        //人脸检测失败或未检测到人脸的情况
                        faceListener.onNoRect();
                    }
                } else {

                }

                if (faceRecognizeRunnables != null && faceRecognizeRunnables.size() > 0) {
                    executor.execute(faceRecognizeRunnables.poll());
                }
            }
            faceEngine.unInit();
            nv21Data = null;
            frThreadRunning = false;
        }

        private void drawPreviewInfo(List<FaceInfo> faceInfoList) {
            List<Rect> rectInfoList = new ArrayList<>();
            for (int i = 0; i < faceInfoList.size(); i++) {
                FaceInfo item=faceInfoList.get(i);
                rectInfoList.add(item.getRect());
            }
            if(faceListener!=null){
                faceListener.onDrawRect(rectInfoList);
            }
        }
    }

    public static final class Builder {
        private Context context;
        private FaceRectView.FaceListener faceListener;
        private int frThreadNum;
        public Builder() {
        }
        public Builder setContext(Context context) {
            this.context = context;
            return this;
        }
        public Builder setFaceListener(FaceRectView.FaceListener faceListener) {
            this.faceListener = faceListener;
            return this;
        }

        public Builder frThreadNum(int val) {
            this.frThreadNum = val;
            return this;
        }

        public RecognizeService build() {
            return new RecognizeService(this);
        }
    }
}
